home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / misc1 / iv26_w30.zip / SOURCES / TEXTEDIT.C < prev    next >
C/C++ Source or Header  |  1991-12-21  |  17KB  |  608 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Stanford not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Stanford makes no representations about
  11.  * the suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22.  
  23. /*
  24.  * TextEditor - basic interactive editor for mulit-line text
  25.  */
  26.  
  27. #include <InterViews/bitmap.h>
  28. #include <InterViews/cursor.h>
  29. #include <InterViews/event.h>
  30. #include <InterViews/font.h>
  31. #include <InterViews/painter.h>
  32. #include <InterViews/perspective.h>
  33. #include <InterViews/shape.h>
  34. #include <InterViews/textbuffer.h>
  35. #include <InterViews/textdisplay.h>
  36. #include <InterViews/texteditor.h>
  37.  
  38. #include <InterViews/Bitmaps/hand.bm>
  39. #include <InterViews/Bitmaps/handm.bm>
  40. #include <InterViews/Bitmaps/dfast.bm>
  41. #include <InterViews/Bitmaps/dfastm.bm>
  42. #include <InterViews/Bitmaps/ufast.bm>
  43. #include <InterViews/Bitmaps/ufastm.bm>
  44.  
  45. #include <ctype.h>
  46. #include <memory.h>
  47. #include <string.h>
  48.  
  49. /*****************************************************************************/
  50.  
  51. static void ScrollAlign (Alignment a, Coord& w, Coord& h) {
  52.     switch (a) {
  53.     case TopLeft:
  54.     case CenterLeft:
  55.     case BottomLeft:
  56.     case Left:
  57.     case Top:
  58.     case Bottom:
  59.     case VertCenter:
  60.     w = 0;
  61.     break;
  62.     case TopCenter:
  63.     case Center:
  64.     case BottomCenter:
  65.     case HorizCenter:
  66.     w = w/2;
  67.     break;
  68.     }
  69.  
  70.     switch (a) {
  71.     case CenterLeft:
  72.     case Center:
  73.     case CenterRight:
  74.     case Left:
  75.     case Right:
  76.     case HorizCenter:
  77.     case VertCenter:
  78.     h = h/2;
  79.     break;
  80.     case BottomLeft:
  81.     case BottomCenter:
  82.     case BottomRight:
  83.     case Bottom:
  84.     h = 0;
  85.     break;
  86.     }
  87. }
  88.  
  89. /*****************************************************************************/
  90.  
  91. TextEditor::TextEditor (int r, int c, int t, int h) {
  92.     Init(r, c, t, h);
  93. }
  94.  
  95. TextEditor::TextEditor (const char* name, int r, int c, int t, int h) {
  96.     SetInstance(name);
  97.     Init(r, c, t, h);
  98. }
  99.  
  100. void TextEditor::Init (int r, int c, int t, int h) {
  101.     SetClassName("TextEditor");
  102.     text = nil;
  103.     dot = 0;
  104.     mark = 0;
  105.     shaperows = r;
  106.     shapecolumns = c;
  107.     scrollalign = Center;
  108.     lineheight = 1;
  109.     tabsize = t;
  110.     highlight = h;
  111.     display = nil;
  112.     perspective = new Perspective();
  113. }
  114.  
  115. TextEditor::~TextEditor () {
  116.     delete display;
  117.     Unref(perspective);
  118. }
  119.  
  120. static Cursor* handCursor;
  121. static Cursor* upCursor;
  122. static Cursor* dnCursor;
  123.  
  124. void TextEditor::Reconfig () {
  125.     if (handCursor == nil) {
  126.         Bitmap hand(
  127.             hand_bits, hand_width, hand_height, hand_x_hot, hand_y_hot
  128.         );
  129.         Bitmap handmask(hand_mask_bits, hand_mask_width, hand_mask_height);
  130.         Bitmap up(
  131.             ufast_bits, ufast_width, ufast_height, ufast_x_hot, ufast_y_hot
  132.         );
  133.         Bitmap upmask(ufast_mask_bits, ufast_mask_width, ufast_mask_height);
  134.         Bitmap dn(
  135.             dfast_bits, dfast_width, dfast_height, dfast_x_hot, dfast_y_hot
  136.         );
  137.         Bitmap dnmask(dfast_mask_bits, dfast_mask_width, dfast_mask_height);
  138.  
  139.         handCursor = new Cursor(
  140.             &hand, &handmask, output->GetFgColor(), output->GetBgColor()
  141.         );
  142.         upCursor = new Cursor(
  143.             &up, &upmask, output->GetFgColor(), output->GetBgColor()
  144.         );
  145.         dnCursor = new Cursor(
  146.             &dn, &dnmask, output->GetFgColor(), output->GetBgColor()
  147.         );
  148.     }
  149.  
  150.     Font* f = output->GetFont();
  151.     shape->hunits = f->Width("n");
  152.     shape->vunits = f->Height();
  153.     shape->Rect(shape->hunits*shapecolumns, shape->vunits*shaperows);
  154.     shape->Rigid(hfil, hfil, vfil, vfil);
  155.     lineheight = shape->vunits;
  156.     display->LineHeight(lineheight);
  157.     display->TabWidth(tabsize * shape->hunits);
  158. }
  159.  
  160. void TextEditor::Resize () {
  161.     if (canvas != nil) {
  162.         display->Draw(output, canvas);
  163.         display->Resize(0, 0, xmax, ymax);
  164.         int topmargin = (
  165.             perspective->height - perspective->curheight - perspective->cury
  166.         );
  167.         Coord height = ymax + 1;
  168.         Coord width = xmax + 1;
  169.         perspective->sy = shape->vunits;
  170.         perspective->ly = height - shape->vunits;
  171.         perspective->sx = shape->hunits;
  172.         perspective->ly = width - shape->hunits;
  173.         perspective->height = display->Height();
  174.         perspective->width = display->Width();
  175.         perspective->cury = perspective->height - topmargin - height;
  176.         perspective->curheight = height;
  177.         perspective->curwidth = width;
  178.         perspective->Update();
  179.     }
  180. }
  181.  
  182. void TextEditor::Redraw (Coord l, Coord b, Coord r, Coord t) {
  183.     if (canvas != nil) {
  184.         display->Draw(output, canvas);
  185.         display->Redraw(l, b, r, t);
  186.     }
  187. }
  188.  
  189. void TextEditor::Adjust (Perspective& np) {
  190.     float scale = float(perspective->height) / float(np.height);
  191.     ScrollTo(
  192.         perspective->x0 + int((np.curx - np.x0)*scale),
  193.         perspective->y0 + int((np.cury - np.y0)*scale)
  194.     );
  195.     np = *perspective;
  196. }
  197.  
  198. void TextEditor::Edit (TextBuffer* t, int index) {
  199.     delete display;
  200.     display = new TextDisplay();
  201.     display->Draw(output, canvas);
  202.     display->LineHeight(lineheight);
  203.     display->TabWidth(tabsize * shape->hunits);
  204.     text = t;
  205.     int lines = text->Height();
  206.     for (int i = 0; i < lines; ++i) {
  207.         int bol = text->LineIndex(i);
  208.         int eol = text->EndOfLine(bol);
  209.         display->ReplaceText(i, text->Text(bol, eol), eol - bol);
  210.     }
  211.     perspective->height = display->Height();
  212.     perspective->width = display->Width();
  213.     perspective->curheight = ymax + 1;
  214.     perspective->curwidth = xmax + 1;
  215.     perspective->cury = perspective->height - perspective->curheight;
  216.     perspective->curx = 0;
  217.     perspective->Update();
  218.  
  219.     Canvas* c = canvas;
  220.     canvas = nil;
  221.     display->Resize(0, 0, xmax, ymax);
  222.     Select(index);
  223.     ScrollToSelection(true);
  224.     canvas = c;
  225.     display->Draw(output, canvas);
  226.     display->Redraw(0, 0, xmax, ymax);
  227. }
  228.  
  229. void TextEditor::InsertText (const char* s, int count) {
  230.     count = text->Insert(dot, s, count);
  231.     int sline = text->LineNumber(dot);
  232.     int fline = text->LineNumber(dot + count);
  233.     display->Draw(output, canvas);
  234.     if (sline == fline) {
  235.         int offset = text->LineOffset(dot);
  236.         display->InsertText(sline, offset, text->Text(dot), count);
  237.     } else {
  238.         display->InsertLinesAfter(sline, fline-sline);
  239.         for (int i = sline; i <= fline; ++i) {
  240.             int bol = text->BeginningOfLine(text->LineIndex(i));
  241.             int eol = text->EndOfLine(bol);
  242.             display->ReplaceText(i, text->Text(bol, eol), eol-bol);
  243.         }
  244.     }
  245.     if (canvas != nil) {
  246.         int width = display->Width();
  247.         int height = display->Height();
  248.         if (width != perspective->width || height != perspective->height) {
  249.             perspective->cury += height - perspective->height;
  250.             perspective->height = height;
  251.             perspective->width = width;
  252.             perspective->Update();
  253.         }
  254.     }
  255.     Select(dot + count);
  256. }
  257.  
  258. void TextEditor::DeleteText (int count) {
  259.     int start = dot;
  260.     int finish = dot;
  261.     int c = count;
  262.     while (c > 0) {
  263.         finish = text->NextCharacter(finish);
  264.         --c;
  265.     }
  266.     while (c < 0) {
  267.         start = text->PreviousCharacter(start);
  268.         ++c;
  269.     }
  270.     count = finish - start;
  271.     int sline = text->LineNumber(start);
  272.     int fline = text->LineNumber(finish);
  273.     text->Delete(start, count);
  274.     display->Draw(output, canvas);
  275.     if (sline == fline) {
  276.         int offset = text->LineOffset(start);
  277.         display->DeleteText(sline, offset, count);
  278.     } else {
  279.         int bol = text->BeginningOfLine(start);
  280.         int eol = text->EndOfLine(start);
  281.         display->DeleteLinesAfter(sline, fline-sline);
  282.         display->ReplaceText(sline, text->Text(bol, eol), eol-bol);
  283.     }
  284.     if (canvas != nil) {
  285.         int width = display->Width();
  286.         int height = display->Height();
  287.         if (width != perspective->width || height != perspective->height) {
  288.             perspective->cury += height - perspective->height;
  289.             perspective->height = height;
  290.             perspective->width = width;
  291.             perspective->Update();
  292.         }
  293.     }
  294.     Select(start);
  295. }
  296.  
  297. void TextEditor::DeleteSelection () {
  298.     if (mark != dot) {
  299.         DeleteText(mark - dot);
  300.     }
  301. }
  302.  
  303. void TextEditor::BeginningOfSelection () {
  304.     Select(min(mark, dot));
  305. }
  306.  
  307. void TextEditor::EndOfSelection () {
  308.     Select(max(mark, dot));
  309. }
  310.  
  311. void TextEditor::BeginningOfWord () {
  312.     if (dot != mark) {
  313.         Select(min(mark, dot));
  314.     } else {
  315.         Select(text->BeginningOfWord(dot));
  316.     }
  317. }
  318.  
  319. void TextEditor::EndOfWord () {
  320.     if (dot != mark) {
  321.         Select(max(mark, dot));
  322.     } else {
  323.         Select(text->EndOfWord(dot));
  324.     }
  325. }
  326.  
  327. void TextEditor::BeginningOfLine () {
  328.     if (dot != mark) {
  329.         Select(min(mark, dot));
  330.     } else {
  331.         Select(text->BeginningOfLine(dot));
  332.     }
  333. }
  334.  
  335. void TextEditor::EndOfLine () {
  336.     if (dot != mark) {
  337.         Select(max(mark, dot));
  338.     } else {
  339.         Select(text->EndOfLine(dot));
  340.     }
  341. }
  342.  
  343. void TextEditor::BeginningOfText() {
  344.     Select(text->BeginningOfText());
  345. }
  346.  
  347. void TextEditor::EndOfText() {
  348.     Select(text->EndOfText());
  349. }
  350.  
  351. void TextEditor::ForwardCharacter (int count) {
  352.     if (mark != dot) {
  353.         Select(max(mark, dot));
  354.     } else {
  355.         int d = dot;
  356.         while (count > 0) {
  357.             d = text->NextCharacter(d);
  358.             --count;
  359.         }
  360.         Select(d);
  361.     }
  362. }
  363.  
  364. void TextEditor::BackwardCharacter (int count) {
  365.     if (dot != mark) {
  366.         Select(min(mark, dot));
  367.     } else {
  368.         int d = dot;
  369.         while (count > 0) {
  370.             d = text->PreviousCharacter(d);
  371.             --count;
  372.         }
  373.         Select(d);
  374.     }
  375. }
  376.  
  377. void TextEditor::ForwardLine (int count) {
  378.     if (dot != mark) {
  379.         Select(max(mark, dot));
  380.     } else {
  381.         int d = dot;
  382.         while (count > 0) {
  383.             d = text->BeginningOfNextLine(d);
  384.             --count;
  385.         }
  386.         Select(d);
  387.     }
  388. }
  389.  
  390. void TextEditor::BackwardLine (int count) {
  391.     if (dot != mark) {
  392.         Select(min(mark, dot));
  393.     } else {
  394.         int d = dot;
  395.         while (count > 0) {
  396.             d = text->BeginningOfLine(text->EndOfPreviousLine(d));
  397.             --count;
  398.         }
  399.         Select(d);
  400.     }
  401. }
  402.  
  403. void TextEditor::ForwardWord (int count) {
  404.     if (dot != mark) {
  405.         Select(max(mark, dot));
  406.     } else {
  407.         int d = dot;
  408.         while (count > 0) {
  409.             d = text->BeginningOfNextWord(d);
  410.             --count;
  411.         }
  412.         Select(d);
  413.     }
  414. }
  415.  
  416. void TextEditor::BackwardWord (int count) {
  417.     if (dot != mark) {
  418.         Select(min(mark, dot));
  419.     } else {
  420.         int d = dot;
  421.         while (count > 0) {
  422.             d = text->BeginningOfWord(text->EndOfPreviousWord(d));
  423.             --count;
  424.         }
  425.         Select(d);
  426.     }
  427. }
  428.  
  429. void TextEditor::ForwardPage (int count) {
  430.     int pagesize = perspective->curheight / perspective->sy;
  431.     ForwardLine(pagesize * count);
  432. }
  433.  
  434. void TextEditor::BackwardPage (int count) {
  435.     int pagesize = perspective->curheight / perspective->sy;
  436.     BackwardLine(pagesize * count);
  437. }
  438.  
  439. void TextEditor::ScrollToSelection (boolean always) {
  440.     display->Draw(output, canvas);
  441.     int line = text->LineNumber(dot);
  442.     int offset = text->LineOffset(dot);
  443.     Coord l = display->Left(line, offset);
  444.     Coord r = display->Right(line, offset);
  445.     Coord b = display->Base(line);
  446.     Coord t = display->Top(line);
  447.  
  448.     Coord tx = xmax - (r - l);
  449.     Coord ty = ymax - (t - b);
  450.     ScrollAlign(scrollalign, tx, ty);
  451.  
  452.     Coord dx = (always || l < 0 || r > xmax) ? l - tx : 0;
  453.     Coord dy = (always || b < 0 || t > ymax) ? b - ty : 0;
  454.  
  455.     if (dx != 0 || dy != 0) {
  456.         ScrollTo(perspective->curx + dx, perspective->cury + dy);
  457.     }
  458. }
  459.  
  460. void TextEditor::ScrollToView (Coord x, Coord y) {
  461.     Coord dx = x < 0 ? x : x > xmax ? x - xmax : 0;
  462.     Coord dy = y < 0 ? y : y > ymax ? y - ymax : 0;
  463.     if (dx != 0 || dy != 0) {
  464.         ScrollTo(perspective->curx + dx, perspective->cury + dy);
  465.     }
  466. }
  467.  
  468. void TextEditor::ScrollBy (int dx, int dy) {
  469.     if (dx != 0 || dy != 0) {
  470.         ScrollTo(perspective->curx + dx, perspective->cury + dy);
  471.     }
  472. }
  473.  
  474. void TextEditor::ScrollTo (int x, int y) {
  475.     int maxy = perspective->height - perspective->curheight;
  476.     int miny = min(maxy, -perspective->curheight/2);
  477.     perspective->cury = max(miny, min(y, maxy));
  478.     int minx = 0;
  479.     int maxx = max(minx, perspective->width - perspective->curwidth/2);
  480.     perspective->curx = max(minx, min(x, maxx));
  481.     perspective->Update();
  482.     display->Scroll(0,
  483.         - perspective->curx,
  484.         ymax + perspective->height - (perspective->cury+perspective->curheight)
  485.     );
  486. }
  487.  
  488. void TextEditor::Select (int d) {
  489.     Select(d, d);
  490. }
  491.  
  492. void TextEditor::SelectMore (int m) {
  493.     Select(dot, m);
  494. }
  495.  
  496. void TextEditor::SelectAll () {
  497.     Select(text->EndOfText(), text->BeginningOfText());
  498. }
  499.  
  500. void TextEditor::Select (int d, int m) {
  501.     int oldl = min(dot, mark);
  502.     int oldr = max(dot, mark);
  503.     int newl = min(d, m);
  504.     int newr = max(d, m);
  505.     display->Draw(output, canvas);
  506.     if (oldl == oldr && newl != newr) {
  507.         display->CaretStyle(NoCaret);
  508.     }
  509.     if (newr < oldl || newl > oldr) {
  510.         if (oldr > oldl) {
  511.             display->RemoveStyle(
  512.                 text->LineNumber(oldl), text->LineOffset(oldl),
  513.                 text->LineNumber(oldr-1), text->LineOffset(oldr-1),
  514.                 highlight
  515.             );
  516.         }
  517.         if (newr > newl) {
  518.             display->AddStyle(
  519.                 text->LineNumber(newl), text->LineOffset(newl),
  520.                 text->LineNumber(newr-1), text->LineOffset(newr-1),
  521.                 highlight
  522.             );
  523.         }
  524.     } else {
  525.         if (newl < oldl) {
  526.             display->AddStyle(
  527.                 text->LineNumber(newl), text->LineOffset(newl),
  528.                 text->LineNumber(oldl-1), text->LineOffset(oldl-1),
  529.                 highlight
  530.             );
  531.         } else if (newl > oldl) {
  532.             display->RemoveStyle(
  533.                 text->LineNumber(oldl), text->LineOffset(oldl),
  534.                 text->LineNumber(newl-1), text->LineOffset(newl-1),
  535.                 highlight
  536.             );
  537.         }
  538.         if (newr > oldr) {
  539.             display->AddStyle(
  540.                 text->LineNumber(oldr), text->LineOffset(oldr),
  541.                 text->LineNumber(newr-1), text->LineOffset(newr-1),
  542.                 highlight
  543.             );
  544.         } else if (newr < oldr) {
  545.             display->RemoveStyle(
  546.                 text->LineNumber(newr), text->LineOffset(newr),
  547.                 text->LineNumber(oldr-1), text->LineOffset(oldr-1),
  548.                 highlight
  549.             );
  550.         }
  551.     }
  552.     if (oldl != oldr && newl == newr) {
  553.         display->CaretStyle(BarCaret);
  554.     }
  555.     if (newl == newr) {
  556.         display->Caret(text->LineNumber(newl), text->LineOffset(newl));
  557.     }
  558.     dot = d;
  559.     mark = m;
  560. }
  561.  
  562. int TextEditor::Locate (Coord x, Coord y) {
  563.     display->Draw(output, canvas);
  564.     int line = display->LineNumber(y);
  565.     int index = display->LineIndex(line, x);
  566.     int l = text->LineIndex(line);
  567.     int i = 0;
  568.     while (i < index) {
  569.         l = text->NextCharacter(l);
  570.         i += 1;
  571.     }
  572.     return l;
  573. }
  574.  
  575. void TextEditor::GrabScroll (Event& e) {
  576.     int y = e.y;
  577.     int x = e.x;
  578.     Cursor* origCursor = GetCursor();
  579.     SetCursor(handCursor);
  580.  
  581.     do {
  582.         ScrollBy(0, y - e.y);
  583.         y = e.y;
  584.         x = e.x;
  585.         Poll(e);
  586.     } while (e.middlemouse);
  587.  
  588.     SetCursor(origCursor);
  589. }
  590.  
  591. void TextEditor::RateScroll (Event& e) {
  592.     Cursor* origCursor = GetCursor();
  593.     int y = e.y;
  594.     int x = e.x;
  595.  
  596.     do {
  597.         ScrollBy(0, e.y - y);
  598.         if (e.y - y < 0) {
  599.             SetCursor(dnCursor);
  600.         } else {
  601.             SetCursor(upCursor);
  602.         }
  603.         Poll(e);
  604.     } while (e.rightmouse);
  605.  
  606.     SetCursor(origCursor);
  607. }
  608.